#include "Patch.h"

namespace PUMA
{
	Geometry::Geometry(void)
	{
		isInited = false;
		mVertexVBO = QGLBuffer(QGLBuffer::VertexBuffer);
		mIndexVBO = QGLBuffer(QGLBuffer::IndexBuffer);
	}

	void Geometry::initBuffers(QGLBuffer::UsagePattern usage)
	{
		if(isInited)
			return;
		mVertexVBO.create();
		mIndexVBO.create();

		mVertexVBO.bind();
		mIndexVBO.bind();

		mVertexVBO.setUsagePattern(usage);
		mIndexVBO.setUsagePattern(usage);

		mVertexVBO.allocate(vertices.data(), sizeof(MyVertex)*vertices.count());
		mIndexVBO.allocate(indices.data(), sizeof(GLuint)*indices.count());
	
		mVertexVBO.release();
		mIndexVBO.release();
	}

	void Geometry::appendTriangleIndices(const int a, const int b, const int c)
	{
		indices.append(a);
		indices.append(b);
		indices.append(c);
	}

	void Geometry::finalize()
	{
		// TODO something can be done, ie. normal vectors normalization
	}

	void Geometry::appendFaceted(const QVector3D &a, const QVector3D &n)
	{
		int v = vertices.count();
		vertices.append(MyVertex(a,n));
	}

	void Geometry::bind()
	{
		mVertexVBO.bind();
		mIndexVBO.bind();
	}
	
	void Geometry::release()
	{
		mVertexVBO.release();
		mIndexVBO.release();
	}
	// Start PATCH definition

	Patch::Patch(Geometry * g): geom(g)
	{
	}


	Patch::~Patch(void)
	{
		delete geom;
	}

	void Patch::draw(QGLShaderProgram& shaderProgram, QMatrix4x4& viewMatrix, QMatrix4x4& projectionMatrix) const
	{
		// initialize geometry on the graphic card
		geom->initBuffers(QGLBuffer::StaticDraw);
		geom->bind();
	
		shaderProgram.bind();

		int inPositionLocation = shaderProgram.attributeLocation("inPosition");
		int inColorLocation = shaderProgram.attributeLocation("inColor");
		int inNormalLocation = shaderProgram.attributeLocation("inNormal");

		int inModelMatrixLocation = shaderProgram.uniformLocation("inModelMatrix");
		int inViewMatrixLocation = shaderProgram.uniformLocation("inViewMatrix");
		int inProjectionMatrixLocation = shaderProgram.uniformLocation("inProjectionMatrix");

		shaderProgram.enableAttributeArray(inPositionLocation);
		shaderProgram.enableAttributeArray(inColorLocation);

		shaderProgram.setAttributeBuffer(inPositionLocation, GL_FLOAT, 0, 3, sizeof(MyVertex));
		shaderProgram.setAttributeBuffer(inColorLocation, GL_FLOAT, 12, 3, sizeof(MyVertex));
		shaderProgram.setAttributeBuffer(inNormalLocation, GL_FLOAT, 24, 3, sizeof(MyVertex));
		shaderProgram.setUniformValue(inModelMatrixLocation, modelMatrix);
		shaderProgram.setUniformValue(inViewMatrixLocation, viewMatrix);
		shaderProgram.setUniformValue(inProjectionMatrixLocation, projectionMatrix);

		glDrawElements(GL_TRIANGLES, geom->indices.count(), GL_UNSIGNED_INT, 0);

		shaderProgram.disableAttributeArray(inPositionLocation);
		shaderProgram.disableAttributeArray(inColorLocation);
	
		// cleanUp
		shaderProgram.release();
		geom->release();
	}

	void Patch::rotate(qreal deg, QVector3D axis)
	{
		modelMatrix.rotate(deg, axis);
	}

	void Patch::translate(const QVector3D &t)
	{
		modelMatrix.translate(t);
	}

	void Patch::addTri(const QVector3D &a, const QVector3D &b, const QVector3D &c, const QVector3D &n)
	{
		QVector3D norm = n.isNull() ? QVector3D::normal(a, b, c) : n;

		geom->appendFaceted(a, norm);
		geom->appendFaceted(b, norm);
		geom->appendFaceted(c, norm);
	}

	// END PATCH definition
}